#!/usr/bin/python
# -*- coding: utf-8 -*-

import Ice, IceGrid
import sys, os, array, thread, time, Image

try:
    HOME = os.environ['RENDERING_CLUSTER']
except KeyError:
    print 'RENDERING_CLUSTER environment variable is not currently defined.'
    sys.exit(0)

SLICE = os.path.join(HOME, 'slice')
FILE = os.path.join(SLICE, 'Cluster.ice')
Ice.loadSlice('--all -I/usr/share/slice', ['-I' + SLICE, FILE])

CONFIG_FILE = os.path.join(HOME, 'config', 'config.client')

BLENDER_DIR = os.path.join(HOME, 'src', 'blend')
PROJECT_NAME = 'project.blend'
PROJECT_FILE = os.path.join(BLENDER_DIR, PROJECT_NAME)
BLENDER_SCRIPT = os.path.join('.', 'BlenderScript.py')

AUX_FILE = os.path.join('blend', 'aux.txt')

import Cluster

class AMI_Model_renderI (object):

    def AMI_Model_renderI ():
	pass
	


    def ice_response (self, done, output):
        if done:
	    endResponseTime = time.time()
            totalResponseTime = endResponseTime-output.startResponseTime
            print 'Frame ' + str(output.frameNumber) + ' done!'
            print 'Response time: ' + str(totalResponseTime)
	    
            sFrameNumber = str(output.frameNumber)
	    sLen = len(sFrameNumber)
            for i in range(0,5-sLen):
		aux = "0"
		sFrameNumber = aux + sFrameNumber
	    		

            path = os.path.join(BLENDER_DIR, str(sFrameNumber) + '.png')
	    print "Saved: " + str(path)
            array.array('B', output.data).tofile(open(path, 'w'))
            print 'Render time: ' + str(output.renderTime)
	    self.__mutex.acquire()	
	    self.__completed[output.frameNumber] = True
	    self.__mutex.release()
        else:
	    self.__mutex.acquire()
	    self.__completed[output.frameNumber] = True
	    self.__mutex.release()
            print 'Frame ' + str(output.frameNumber) + ' failed!'

	finished = True
	self.__mutex.acquire()
	for b in self.__completed[1:]:
	    if not b:
		finished = False
        self.__mutex.release()
	if finished:
	    self.composeVideo(path)
		    	

    def ice_exception (self, ex):
        print 'Rendering error: ' + str(ex)

    def setConcurrencyParameters (self,completed, mutex, startProcessTime):
        self.__completed = completed
	self.__mutex = mutex
	self.__startProcessTime = startProcessTime

    def composeVideo (self, path): 
	
	image = Image.open(path)
	resx, resy = image.size
	imagespath = os.path.join(HOME, 'src', 'blend')
	videopath = str(os.path.join(imagespath,'videos','composed.avi'))

	command = "mencoder 'mf://" + str(imagespath) + "/*.png' -mf w=" + str(resx) + ":h=" + str(resy) + ":fps=25:type=png -of avi -ovc lavc -o " + str(videopath)
	os.system(command)
	print "Video composed. Total time: " + str(time.time() - self.__startProcessTime)

class Client (Ice.Application):

    def run (self, argv):

        self.shutdownOnInterrupt()
	query = IceGrid.QueryPrx.checkedCast(self.communicator().stringToProxy("RenderCluster/Query"))
        base = query.findObjectByType('::Cluster::RenderNode')
        render = Cluster.RenderNodePrx.checkedCast(base)
        startProcessTime = time.time()


        replicas = query.findAllReplicas(base)

        project = array.array('B', open(PROJECT_FILE).read()).tolist()
        nodeCounter = 0.0
        startTransfer = time.time()
        for rep in replicas:
            nodeCounter += 1.0
            prx = Cluster.RenderNodePrx.checkedCast(rep)
            startTime = time.time()
            prx.setProject(project)
            endTime = time.time()
            print 'Node ' + str(nodeCounter) + ' notified. Time: ' + str(endTime-startTime)

        endTransfer = time.time()
        totalTransfer =  endTransfer-startTransfer
        transferAverage = totalTransfer/nodeCounter
        print 'Render nodes notified.'
        print 'Total transfer time: ' + str(totalTransfer)
        print 'Average transfer time: ' + str(transferAverage)

        command = 'blender -b ' + PROJECT_FILE + ' -P ' + BLENDER_SCRIPT
        os.system(command)

        f = open(AUX_FILE, 'r')
        l = f.readline()
        aux = l.split()
        begin, end = int(aux[0]), int(aux[1])
	
	completed = []
	mutex = thread.allocate_lock()	
	completed.append(False) #Count starts in 1
        for i in range (begin, end):
	    base = self.communicator().stringToProxy('RenderNode')
	    base.ice_connectionCached(False)
	    base.ice_locatorCacheTimeout(0)
            render = Cluster.RenderNodePrx.checkedCast(base)
	    #render = Cluster.RenderNodePrx.checkedCast(replicas[i%len(replicas)])	
	    ami = AMI_Model_renderI()
	    completed.append(False)
	    ami.setConcurrencyParameters(completed,mutex, startProcessTime)
            render.render_async(ami, i)

        self.communicator().waitForShutdown()

        return 0

Client().main(sys.argv, CONFIG_FILE)
